﻿using ExDUIR.NET.Canvas;
using ExDUIR.NET.Declaration;
using ExDUIR.NET.Handle;
using ExDUIR.NET.Resource;
using System.Runtime.InteropServices.ComTypes;


namespace ExDUIR.NET.Image
{
    public class ExImage
    {
        private readonly ExImageHandle _handle;
        public int Handle => _handle.Handle;
        public bool IsValid => _handle.IsInvalid;
        internal ExImage(ExImageHandle handle)
        {
            _handle = handle;
        }

        internal ExImage(int width, int height)
        {
            int hImg;
            ExAPI._img_create(width, height, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(ExCanvas canvas)
        {
            int hImg;
            ExAPI._img_createfromcanvas(canvas.Handle, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(string wzFilename)
        {
            int hImg;
            ExAPI._img_createfromfile(wzFilename, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(IntPtr hBitmap, IntPtr hPalette, bool fPreAlpha)
        {
            int hImg;
            ExAPI._img_createfromhbitmap(hBitmap, hPalette, fPreAlpha, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(System.Drawing.Bitmap bitmap)
        {
            var data = Utility.Util.BitmapToByte(bitmap);
            int hImg;
            ExAPI._img_createfrommemory(data, (IntPtr)data.Length, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(System.Drawing.Icon icon)
        {
            var data = Utility.Util.IconToByte(icon);
            int hImg;
            ExAPI._img_createfrommemory(data, (IntPtr)data.Length, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(ExIconHandle hIcon)
        {
            int hImg;
            ExAPI._img_createfromhicon(hIcon.Handle, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(byte[] lpData, int dwLen)
        {
            int hImg;
            ExAPI._img_createfrommemory(lpData, (IntPtr)dwLen, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(int width, int height, IntPtr lpData)
        {
            int hImg;
            ExAPI._img_createfrompngbits2(width, height, lpData, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(ExResource res, int atomPath)
        {
            int hImg;
            ExAPI._img_createfromres(res.Handle, atomPath, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        internal ExImage(IStream lpStream)
        {
            int hImg;
            ExAPI._img_createfromstream(lpStream, out hImg);
            _handle = new ExImageHandle(hImg);
        }

        /// <summary>
        /// 粘贴本图像到大图
        /// </summary>
        /// <param name="bigImg">大图</param>
        /// <param name="bigX">大图粘贴位置横坐标</param>
        /// <param name="bigY">大图粘贴位置纵坐标</param>
        /// <param name="retImg">返回新图像</param>
        /// <returns></returns>
        public bool PasteToBigImg(ExImage bigImg, int bigX, int bigY, out ExImage retImg)
        {
            var ret = ExAPI._img_paste(bigImg.Handle, _handle.Handle, bigX, bigY, out var ans);
            retImg = new ExImage(new ExImageHandle(ans));
            return ret;
        }

        /// <summary>
        /// 粘贴小图到本图像
        /// </summary>
        /// <param name="smallImg">小图图像</param>
        /// <param name="x">粘贴本图位置横坐标</param>
        /// <param name="y">粘贴本图位置纵坐标</param>
        /// <param name="retImg">返回新图像</param>
        /// <returns></returns>
        public bool PasteSmallImg(ExImage smallImg, int x, int y, out ExImage retImg)
        {
            var ret = ExAPI._img_paste(_handle.Handle, smallImg.Handle, x, y, out var ans);
            retImg = new ExImage(new ExImageHandle(ans));
            return ret;
        }

        public bool Copy(out int dsgImg)
        {
            return ExAPI._img_copy(_handle.Handle, out dsgImg);
        }

        public bool Copy(int x, int y, int width, int height, out int dsgImg)
        {
            return ExAPI._img_copyrect(_handle.Handle, x, y, width, height, out dsgImg);
        }

        public int FrameCount
        {
            get
            {
                ExAPI._img_getframecount(_handle.Handle, out int nFrameCount);
                return nFrameCount;
            }
        }

        public bool GetFrameDelay(int[] lpDelayAry, out int nFrames)
        {
            return ExAPI._img_getframedelay(_handle.Handle, lpDelayAry, out nFrames);
        }

        public bool GetPixel(int x, int y, out int color)
        {
            return ExAPI._img_getpixel(_handle.Handle, x, y, out color);
        }

        public bool GetSize(out int lpWidth, out int lpHeight)
        {
            return ExAPI._img_getsize(_handle.Handle, out lpWidth, out lpHeight);
        }

        public bool Lock(ExRect RectL, int flags, int PixelFormat, ref ExBitmapData lpLockedBitmapData)
        {
            return ExAPI._img_lock(_handle.Handle, RectL, flags, PixelFormat, ref lpLockedBitmapData);
        }

        public bool RotateFlip(int rfType, out ExImage dstImg)
        {
            var ans = 0;
            var ret = ExAPI._img_rotateflip(_handle.Handle, rfType, out ans);
            dstImg = new ExImage(new ExImageHandle(ans));
            return ret;
        }

        public bool Mask(ExImage srcImg, int nChannel, bool bBlackMask, out ExImage dstImg)
        {
            ExAPI._img_mask(_handle.Handle, srcImg.Handle, nChannel, bBlackMask, out var handle);
            dstImg = new ExImage(new ExImageHandle(handle));
            return true;
        }

        public bool Scale(int dstWidth, int dstHeight, out ExImage dstImg)
        {
            var ans = 0;
            var ret = ExAPI._img_scale(_handle.Handle, dstWidth, dstHeight, out ans);
            dstImg = new ExImage(new ExImageHandle(ans));
            return ret;
        }

        public bool SelectActiveFrame(int nIndex)
        {
            return ExAPI._img_selectactiveframe(_handle.Handle, nIndex);
        }

        public bool SetPixel(int x, int y, int color)
        {
            return ExAPI._img_setpixel(_handle.Handle, x, y, color);
        }

        public bool Unlock(ref ExBitmapData lpLockedBitmapData)
        {
            return ExAPI._img_unlock(_handle.Handle, ref lpLockedBitmapData);
        }

        public void SaveToFile(string lpWzFile)
        {
            ExAPI._img_savetofile(_handle.Handle, lpWzFile);
        }

        public void SaveToMemory(IntPtr lpBuffer)
        {
            ExAPI._img_savetomemory(_handle.Handle, lpBuffer);
        }

        public void Dispose() => _handle.Dispose();
    }
}
